/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package op;

import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 *
 * @author Jonatas
 */
public abstract class EntradaAbstrata implements Comparable, Cloneable, Serializable {

    public enum TipoLigacao {

        PESSOAL, TRABALHO
    }
    TipoLigacao tipo = null;
    String numeroMisterioso;
    Telefone numeroDeOrigem;
    Date dataOrigemLigacao;     // Data e hora vao ser armazenados aqui dentro!!
    String localDaLigacao;
    String tipoDeLigacao;
    String imposto;
    String outroNumeroMisterioso;       // Numero que vem depois do imposto
    Telefone destino;
    Integer duracaoLigacaoSegundos;
    Integer duracaoLigacaoACobrarSegundos;
    Double custo;
    String planoLigacao;

    @Override
    public EntradaAbstrata clone() {

        EntradaAbstrata entrada = null;
        if (this instanceof Ligacao) {
            entrada = new Ligacao();
        } else {
            entrada = new OutrasCobrancas();
        }

        entrada.numeroMisterioso = this.numeroMisterioso;
        entrada.numeroDeOrigem = (this.numeroDeOrigem == null ? null : this.numeroDeOrigem.clone());
        entrada.dataOrigemLigacao = (this.dataOrigemLigacao == null ? null
                : new Date(this.dataOrigemLigacao.getTime()));
        entrada.localDaLigacao = this.localDaLigacao;
        entrada.tipoDeLigacao = this.tipoDeLigacao;
        entrada.imposto = this.imposto;
        entrada.outroNumeroMisterioso = this.outroNumeroMisterioso;
        entrada.destino = (this.destino == null ? null : this.destino.clone());
        entrada.duracaoLigacaoSegundos = this.duracaoLigacaoSegundos;
        entrada.duracaoLigacaoACobrarSegundos = this.duracaoLigacaoACobrarSegundos;
        entrada.custo = this.custo;
        entrada.planoLigacao = this.planoLigacao;
        entrada.tipo = tipo;

        return entrada;

    }

    protected EntradaAbstrata() {
    }

    public Double getCusto() {
        return custo;
    }

    public void setCusto(Double custo) {
        this.custo = custo;
    }

    public Date getDataOrigemLigacao() {
        return dataOrigemLigacao;
    }

    public void setDataOrigemLigacao(Date dataOrigemLigacao) {
        this.dataOrigemLigacao = dataOrigemLigacao;
    }

    public Telefone getDestino() {
        return destino;
    }

    public void setDestino(Telefone destino) {
        this.destino = destino;
    }

    public Integer getDuracaoLigacaoACobrarSegundos() {
        return duracaoLigacaoACobrarSegundos;
    }

    public void setDuracaoLigacaoACobrarSegundos(Integer duracaoLigacaoACobrarSegundos) {
        this.duracaoLigacaoACobrarSegundos = duracaoLigacaoACobrarSegundos;
    }

    public Integer getDuracaoLigacaoSegundos() {
        return duracaoLigacaoSegundos;
    }

    public void setDuracaoLigacaoSegundos(Integer duracaoLigacaoSegundos) {
        this.duracaoLigacaoSegundos = duracaoLigacaoSegundos;
    }

    public String getImposto() {
        return imposto;
    }

    public void setImposto(String imposto) {
        this.imposto = imposto;
    }

    public String getLocalDaLigacao() {
        return localDaLigacao;
    }

    public void setLocalDaLigacao(String localDaLigacao) {
        this.localDaLigacao = localDaLigacao;
    }

    public Telefone getNumeroDeOrigem() {
        return numeroDeOrigem;
    }

    public void setNumeroDeOrigem(Telefone numeroDeOrigem) {
        this.numeroDeOrigem = numeroDeOrigem;
    }

    public String getNumeroMisterioso() {
        return numeroMisterioso;
    }

    public void setNumeroMisterioso(String numeroMisterioso) {
        this.numeroMisterioso = numeroMisterioso;
    }

    public String getOutroNumeroMisterioso() {
        return outroNumeroMisterioso;
    }

    public void setOutroNumeroMisterioso(String outroNumeroMisterioso) {
        this.outroNumeroMisterioso = outroNumeroMisterioso;
    }

    public String getPlanoLigacao() {
        return planoLigacao;
    }

    public void setPlanoLigacao(String planoLigacao) {
        this.planoLigacao = planoLigacao;
    }

    public String getTipoDeLigacao() {
        return tipoDeLigacao;
    }

    public void setTipoDeLigacao(String tipoDeLigacao) {
        this.tipoDeLigacao = tipoDeLigacao;
    }

    public void setTipo(TipoLigacao tipo) {
        this.tipo = tipo;
    }

    public TipoLigacao getTipo() {
        return tipo;
    }

    protected static EntradaAbstrata quebraString(String entrada) {

        String numeroMisterioso;
        Telefone numeroDeOrigem;
        Date dataOrigemLigacao;     // Data e hora vao ser armazenados aqui dentro!!
        String localDaLigacao;
        String tipoDeLigacao;
        String imposto;
        String outroNumeroMisterioso;       // Numero que vem depois do imposto
        Telefone destino = null;
        Integer duracaoLigacaoSegundos;
        Integer duracaoLigacaoACobrarSegundos;
        Double custo;
        String planoLigacao;


        entrada = entrada.concat(" ");

        String[] valores = entrada.split(";");

        if (valores.length != 13) {
            throw new IllegalArgumentException("Entrada invalida. A entrada deve"
                    + "conter 13 argumentos separados por ';'.");
        }

        numeroMisterioso = valores[0];
        numeroDeOrigem = ((valores[1].length() > 0) ? new Telefone(valores[1]) : null);

        String data = valores[2];
        String hora = valores[3];

        if ((data.length() > 0) && (hora.length() > 0)) {
            dataOrigemLigacao = criaDate(data, hora);
        } else {
            dataOrigemLigacao = null;
        }

        localDaLigacao = valores[4];
        tipoDeLigacao = valores[5];
        imposto = valores[6];
        outroNumeroMisterioso = valores[7];
        try {
            destino = ((valores[8].length() > 0) ? new Telefone(valores[8]) : null);
        } catch (Exception e) {
            System.out.println(valores[8]);
            e.printStackTrace();
        }

        Integer duracao = (valores[9].length() > 0 ? getDuracaoLigacaoSegundos(valores[9]) : null);

        custo = (valores[11].length() > 0 ? new Double(valores[11]) : null);

        planoLigacao = valores[5].trim();

        if (numeroDeOrigem != null && destino != null && (duracao != null)) {
            EntradaAbstrata ligacao = new Ligacao();

            ligacao.setCusto(custo);
            ligacao.setDataOrigemLigacao(dataOrigemLigacao);
            ligacao.setDestino(destino);
            ligacao.setLocalDaLigacao(localDaLigacao);

            if (localDaLigacao.toLowerCase().contains("cobrar")) {
                ligacao.setDuracaoLigacaoACobrarSegundos(duracao);
                ligacao.setDuracaoLigacaoSegundos(null);
            } else {
                ligacao.setDuracaoLigacaoACobrarSegundos(null);
                ligacao.setDuracaoLigacaoSegundos(duracao);
            }

            ligacao.setImposto(imposto);

            ligacao.setNumeroDeOrigem(numeroDeOrigem);
            ligacao.setNumeroMisterioso(numeroMisterioso);
            ligacao.setOutroNumeroMisterioso(outroNumeroMisterioso);

            if (custo.doubleValue() == 0.0) {
                planoLigacao += " franqueada";
            }

            ligacao.setPlanoLigacao(planoLigacao);
            ligacao.setTipoDeLigacao(tipoDeLigacao);

            return ligacao;

        } else {
            EntradaAbstrata ligacao = new OutrasCobrancas();

            ligacao.setCusto(custo);
            ligacao.setDataOrigemLigacao(dataOrigemLigacao);
            ligacao.setDestino(destino);
            ligacao.setDuracaoLigacaoACobrarSegundos(null);
            ligacao.setDuracaoLigacaoSegundos(null);
            ligacao.setImposto(imposto);
            ligacao.setLocalDaLigacao(localDaLigacao);
            ligacao.setNumeroDeOrigem(numeroDeOrigem);
            ligacao.setNumeroMisterioso(numeroMisterioso);
            ligacao.setOutroNumeroMisterioso(outroNumeroMisterioso);
            ligacao.setPlanoLigacao(planoLigacao);
            ligacao.setTipoDeLigacao(tipoDeLigacao);

            return ligacao;
        }

    }

    public static Integer getDuracaoLigacaoSegundos(String hora) {

        Pattern numero = Pattern.compile("[0-9]+");
        Matcher match = numero.matcher(hora);

        match.find();
        int hh = Integer.parseInt(match.group());
        match.find();
        int mm = Integer.parseInt(match.group());
        match.find();
        int ss = Integer.parseInt(match.group());

        int segundos = (hh * 60 * 60) + (mm * 60) + ss;

        return new Integer(segundos);

    }

    public static Date criaDate(String data, String hora) {

        Calendar calendar = Calendar.getInstance();

        int dia = Integer.parseInt(data.substring(0, 2));
        int mes = Integer.parseInt(data.substring(3, 5));
        String anoStr = (data.substring(6).length() == 2 ? "20" + data.substring(6) : data.substring(6));
        int ano = Integer.parseInt(anoStr);

        int hh = Integer.parseInt(hora.substring(0, 2));
        int mm = Integer.parseInt(hora.substring(3, 5));
        int ss = Integer.parseInt(hora.substring(6));


        calendar.set(ano, (mes - 1), dia, hh, mm, ss);

        return calendar.getTime();
    }

    public String getDuracaoLigacaoHoras() {
        return getDuracaoHoras(duracaoLigacaoSegundos.intValue());
    }

    public String getDuracaoLigacaoACobrarHoras() {
        return getDuracaoHoras(duracaoLigacaoACobrarSegundos.intValue());
    }

    public static String getDuracaoHoras(int tempoSegundos) {
        int hh = tempoSegundos / 3600;
        tempoSegundos %= 3600;

        int mm = tempoSegundos / 60;
        tempoSegundos %= 60;

        String resposta = "" + hh;
        if (resposta.length() == 1) {
            resposta = "0" + resposta;
        }
        resposta += ":";

        String aux = "" + mm;
        if (aux.length() == 1) {
            resposta += "0" + aux;
        } else {
            resposta += aux;
        }
        resposta += ":";

        aux = "" + tempoSegundos;
        if (aux.length() == 1) {
            resposta += "0" + aux;
        } else {
            resposta += aux;
        }

        return resposta;
    }

    public abstract boolean isLigacao();
}
